#include "biteditor.h"
#include "projectexplorer.h"
#include "cmath"


#include <QCheckBox>
#include <QHBoxLayout>
#include <QIntValidator>
#include <QMessageBox>

//------------------- class WidgetBit ------------------------
WidgetBit::WidgetBit(QWidget *parent)
    :
    QWidget(parent)
{
    checkBox = new QCheckBox(this);
    checkBox->setFixedSize(20, 20);

    lblDigital = new QLabel("0  ", this);
    lblDigital->setAlignment(Qt::AlignCenter);
    lblDigital->setFixedSize(20, 20);

    lblNumBit = new QLabel(this);
    lblNumBit->setAlignment(Qt::AlignCenter);
    lblNumBit->setFixedSize(20, 20);

    vLayout = new QVBoxLayout(this);
    vLayout->setSpacing(1);
    vLayout->setMargin(1);

    vLayout->addWidget(lblDigital);
    vLayout->addWidget(checkBox);
    vLayout->addWidget(lblNumBit);

    vLayout->setAlignment(Qt::AlignCenter);

    QObject::connect(checkBox, SIGNAL(clicked(bool)), this, SLOT(on_checkBox_clicked()));
}

WidgetBit::~WidgetBit()
{

}

void WidgetBit::on_checkBox_clicked()
{
    if (checkBox->isChecked()) lblDigital->setText("1  ");
    else lblDigital->setText("0  ");
}

void WidgetBit::setUnit()
{
    checkBox->setChecked(true);
    lblDigital->setText("1  ");
}

void WidgetBit::setZero()
{
    checkBox->setChecked(false);
    lblDigital->setText("0  ");
}

void WidgetBit::setInverse()
{
    checkBox->isChecked() ? setZero() : setUnit();
}

//------------------- class BitEditor ------------------------
BitEditor::BitEditor(int nBit, QWidget *parent) :
        QDialog(parent)
{
    setModal(true);

    lineEdit = new QLineEdit;
    QIntValidator * v = new QIntValidator(lineEdit);
    lineEdit->setValidator(v);
    connect(lineEdit, SIGNAL(textEdited(const QString&)), SLOT(on_lineEdit_textChanged(const QString&)));


    QHBoxLayout * lineLayout = new QHBoxLayout;
    lineLayout->addStretch(1);
    lineLayout->addWidget(lineEdit);

    btnOK = new QPushButton("OK");
    btnOK->setFixedSize(70, 27);
    connect(btnOK, SIGNAL(clicked()), SLOT(close()));

    btnOn = new QPushButton("Set all \"1\"");
    btnOn->setFixedSize(70, 27);
    connect(btnOn, SIGNAL(clicked()), SLOT(on_btnOn_clicked()));

    btnOff = new QPushButton("Set all \"0\"");
    btnOff->setFixedSize(70, 27);
    connect(btnOff, SIGNAL(clicked()), SLOT(on_btnOff_clicked()));

    btnInverse = new QPushButton("Inverse");
    btnInverse->setFixedSize(70, 27);
    connect(btnInverse, SIGNAL(clicked()), SLOT(on_btnInverse_clicked()));

    QHBoxLayout * buttonsLayout = new QHBoxLayout;
    buttonsLayout->addWidget(btnOn);
    buttonsLayout->addWidget(btnOff);
    buttonsLayout->addWidget(btnInverse);
    buttonsLayout->addStretch(1);
    buttonsLayout->addWidget(btnOK);
    buttonsLayout->setAlignment(Qt::AlignTop);

    lblHex = new QLabel("HEX:");
    lblHex->setAlignment(Qt::AlignLeft | Qt::AlignBottom);
    lblHex->setFixedSize(80, 20);

    lblSignDecimal = new QLabel("DEC:");
    lblSignDecimal->setAlignment(Qt::AlignLeft | Qt::AlignBottom);
    lblSignDecimal->setFixedSize(120, 20);

    lblUnsingDecimal = new QLabel("UnsD:");
    lblUnsingDecimal->setAlignment(Qt::AlignLeft | Qt::AlignBottom);
    lblUnsingDecimal->setFixedSize(120, 20);

    QHBoxLayout * valueLayout = new QHBoxLayout;
    valueLayout->addWidget(lblHex);
    valueLayout->addWidget(lblUnsingDecimal);
    valueLayout->addWidget(lblSignDecimal);
    valueLayout->addStretch(3);
    buttonsLayout->setAlignment(Qt::AlignBottom);

    QLabel * lblDigital = new QLabel("Value");
    lblDigital->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
    lblDigital->setFixedSize(30, 20);

    QLabel * lblSpace = new QLabel();
    lblSpace->setFixedSize(30, 20);

    QLabel * lblNumBit = new QLabel("Bit #");
    lblNumBit->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
    lblNumBit->setFixedSize(30, 20);

    QVBoxLayout * vLayout = new QVBoxLayout();
    vLayout->addWidget(lblDigital);
    vLayout->addWidget(lblSpace);
    vLayout->addWidget(lblNumBit);

    QHBoxLayout * bitlayout = new QHBoxLayout;
    bitlayout->setSpacing(0);
    bitlayout->setMargin(0);
    bitlayout->addStretch(1);
    bitlayout->setAlignment(Qt::AlignCenter);

    QGridLayout * gLayout = new QGridLayout;
    gLayout->setHorizontalSpacing(0);
    gLayout->setMargin(0);
    gLayout->addLayout(vLayout, 0, 0, 2, 1, Qt::AlignRight);

    n = nBit;

    for (int i = 0; i < n; i++)
    {
        WidgetBit * wb = new WidgetBit;
        if (i - 1 < 5) wb->lblNumBit->setText(tr("%1").arg(n - i - 1) + " ");
        else wb->lblNumBit->setText(tr ("%1").arg(n - i - 1) + "  ");

        widgetBit.push_back(wb);
        gLayout->addWidget(wb, 0, i + 1 , 1, 1, Qt::AlignRight);
        QObject::connect(wb->checkBox, SIGNAL(clicked(bool)), SLOT(getStrValue()));
    }

    bitlayout->addLayout(gLayout);

    QVBoxLayout * layout = new QVBoxLayout;

    layout->addLayout(valueLayout, Qt::AlignBottom);
    layout->addLayout(lineLayout, Qt::AlignVCenter);
    layout->addLayout(bitlayout, Qt::AlignVCenter);
    layout->addLayout(buttonsLayout, Qt::AlignTop);
    layout->setAlignment(Qt::AlignCenter);

    setLayout(layout);
    btnOK->setFocus();
    setWindowTitle(tr("Bit editor"));
    getStrValue();

 }

BitEditor::~BitEditor()
{

}

QString BitEditor::getBitsValue()
{
    return  bitsValue;
}

void BitEditor::setBitsValue(int value)
{
    on_btnOff_clicked();
    QString result = QString::number((unsigned long)value, 2);

    for (int i = 0; (i < n) && (i < result.length()); i++)
    {
        if ('1' == result[result.length() - 1 - i]) widgetBit[n - 1 - i]->setUnit();
    }
    getStrValue();

}

void BitEditor::on_btnOn_clicked()
{
    QVector<WidgetBit *>::iterator it = widgetBit.begin();
    WidgetBit * wb;
    for (;it != widgetBit.end(); ++it)
    {
        wb = *it;
        wb->setUnit();
    }
    getStrValue();
}

void BitEditor::on_btnOff_clicked()
{
    for (int i = 0; i < n; ++i) widgetBit[i]->setZero();
    getStrValue();
}

void BitEditor::on_btnInverse_clicked()
{
    for (int i = 0; i < n; ++i) widgetBit[i]->setInverse();
    getStrValue();
}

void BitEditor::getStrValue()
{
    unsigned long result = 0;
    unsigned long mask = 1;
    unsigned long delta = 1;

    for (int i = 0; i < n; i++)
    {
        if (widgetBit[n - 1 - i]->checkBox->isChecked()) result |= mask;
        mask <<= 1;
    }
    mask >>= 1;
    mask &= result;
    mask <<= 1;
    delta = mask;

    for (int i = n; i < 32; i++)
    {
        delta |= mask;
        mask <<= 1;
    }

    bitsValue = QString::number(result);
    lineEdit->setText(bitsValue);
    lblHex->setText("HEX: 0x" + QString::number(result, 16));
    lblUnsingDecimal->setText("Unsigned: " + QString::number(result));
    result ^= delta;
    lblSignDecimal->setText("Signed: " + QString::number((signed long)result));
}

void BitEditor::on_lineEdit_textChanged(const QString & str)
{
    setBitsValue(str.toInt());
}



